const defAttr = () => ({
    program: null,
    data: {},//在同一个程序集对象中, 所有Unifrom变量值都是相同的,除非在更新前重新更改,否则会后覆盖前
    // 'u_Color': {
    //     value: [1, 1, 1, 1],
    //     type: 'unifroms4fv',
    //     location: null,
    //     needUpdate: true,
    //     cRend : false, //持续渲染
    // }
    mode: [
        "POINTS",
        "TRIANGLES", "TRIANGLE_STRIP", "TRIANGLE_FAN",
        "LINES", "LINE_STRIP", "LINE_LOOP",
    ],
    maps: {},
    // 'u_Sampler': {
    //     image: image,
    //     texture : textureBuffer,
    //     WRAP_W: gl.CLAMP_TO_EDGE,
    //     WRAP_H: gl.CLAMP_TO_EDGE,
    //     MIN_FILTER: gl.LINEAR,
    //     MAG_FILTER: null,
    //     format: gl.RGB,
    //     flipY: 1,
    //     location: null,
    //     needUpdate: true,
    // }

})

//材质对象
export default class Mat {
    constructor(attr) {
        Object.assign(this, defAttr(), attr);
    }

    init(gl) {
        const { data, maps } = this

        // Object.entries(data).forEach(([key, val], index) => {
        //     val.needUpdate = true;
        //     //继续加上是否需要变换
        //     //用在判断 uniform 变量是否经过了外界的变换
        //     //目前应该是一直是 True
        //     //只有 u_ModelM4 会变成 False
        //     //因为在 Obj3D.allTransform() 中进行了变换
        // });
        Object.entries(maps).forEach(([key, val], index) => {
            if (!val.texture) {
                val.texture = gl.createTexture();
                //感觉这个地方还是需要needUpdate
            }
            this._updateMap(gl, index, val);
        });
    }

    update(gl, uniforms) {
        this._updateData(gl, uniforms);
        this._updateMaps(gl, uniforms);
    }

    _updateData(gl, uniforms) {
        const { data } = this;
        Object.entries(data).forEach(([key, val], index) => {
            const { value, type } = val;
            const location = uniforms.get(key);

            if (type.indexOf('Matrix') == -1) {
                gl[type](location, value);
            } else {
                gl[type](location, false, value);
            }
        });
    }

    _updateMaps(gl, uniforms) {
        const { maps } = this;
        Object.entries(maps).forEach(([key, value], index) => {
            if (value.needUpdate) {
                value.needUpdate = false;
                this._updateMap(gl, index, value);
            } else {
                gl.bindTexture(gl.TEXTURE_2D, value.texture);
            }
            const location = uniforms.get(key);
            gl.uniform1i(location, index);//gl.TEXTURE0激活的是0
        });
    }

    _updateMap(gl, index, value) {
        const {
            image,
            texture,
            WRAP_H,
            WRAP_W,
            MIN_FILTER,
            MAG_FILTER,
            format = gl.RGB,
            flipY = 1,
        } = value;

        if (!texture) {
            val.texture = gl.createTexture();
        }

        //是否反转Y轴
        flipY && gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
        // 激活纹理单元
        gl.activeTexture(gl[`TEXTURE${index}`]);
        gl.bindTexture(gl.TEXTURE_2D, value.texture);
        image && gl.texImage2D(
            gl.TEXTURE_2D,
            0,
            format,
            format,
            gl.UNSIGNED_BYTE,
            image
        );

        //设置非二次幂图片(非二次幂图片只有在边缘加紧时才可以显示)
        WRAP_H && gl.texParameteri(
            gl.TEXTURE_2D,//二维纹理
            gl.TEXTURE_WRAP_T,//纹理容器在t方向的尺寸
            gl.CLAMP_TO_EDGE//边缘加紧的意思
        );
        WRAP_W && gl.texParameteri(
            gl.TEXTURE_2D,//二维纹理
            gl.TEXTURE_WRAP_S,//纹理容器在s方向的尺寸
            gl.CLAMP_TO_EDGE//边缘加紧的意思
        );

        MAG_FILTER && gl.texParameteri(
            gl.TEXTURE_2D,//二维纹理
            gl.TEXTURE_MAG_FILTER,//纹理缩小滤波器(当图片源比显示框大的时候进行等比缩小)
            gl.MAG_FILTER//线性
        );

        if (!MIN_FILTER || MIN_FILTER > 9729) {
            gl.generateMipmap(gl.TEXTURE_2D)
        }

        MIN_FILTER && gl.texParameteri(
            gl.TEXTURE_2D,
            gl.TEXTURE_MIN_FILTER,
            MIN_FILTER
        )
    }

    setData(key, value) {
        const { data } = this;
        if (!data[key]) {
            return;
        }
        // data[key].needUpdate = true;
        Object.assign(data[key], value);
    }

    setMap(key, value) {
        const { maps } = this;
        let map = maps[key];
        if (!map)
            return;
        map.needUpdate = true;
        Object.assign(map, value);
    }

    addMaps(data) {
        Object.assign(this.maps, data);
        const { maps } = this;
        Object.entries(maps).forEach(([key, val], index) => {
            if (!val.texture) {
                val.texture = gl.createTexture();
                //感觉这个地方还是需要needUpdate
            }
            this._updateMap(gl, index, val);
        });
    }

    clone() {
        const { program, mode, data, maps } = this;

        let curData = {};
        Object.entries(data).forEach(([key, val], index) => {
            curData[key] = {
                type: val.type.slice(),
            };
            if (val.type.lastIndexOf('v') == val.type.length - 1) {
                curData[key].value = val.value.concat();
            } else {
                curData[key].value = val.value;
            }
        })

        let curMap = {};
        Object.entries(maps).forEach(([key, val], index) => {
            curMap[key] = {
                image: val.image,
                WRAP_W: val.WRAP_W,
                WRAP_H: val.WRAP_H,
                MIN_FILTER: val.MIN_FILTER,
                MAG_FILTER: val.MAG_FILTER,
                format: val.format,
                flipY: val.flipY,
            };
        })

        return new Mat({
            program: program,
            mode: mode.concat(),
            data: curData,
            maps: curMap,
        });
    }

}